#include <iostream>
#include <stdint.h>
#include <vector>

extern "C" void swap_context(void *, void *) asm("swap_context");
asm(R"(
swap_context:
  mov 0x00(%rsp), %rdx
  lea 0x08(%rsp), %rcx
  mov %r12, 0x00(%rdi)
  mov %r13, 0x08(%rdi)
  mov %r14, 0x10(%rdi)
  mov %r15, 0x18(%rdi)
  mov %rdx, 0x20(%rdi)
  mov %rcx, 0x28(%rdi)
  mov %rbx, 0x30(%rdi)
  mov %rbp, 0x38(%rdi)
  mov 0x00(%rsi), %r12
  mov 0x08(%rsi), %r13
  mov 0x10(%rsi), %r14
  mov 0x18(%rsi), %r15
  mov 0x20(%rsi), %rax
  mov 0x28(%rsi), %rcx
  mov 0x30(%rsi), %rbx
  mov 0x38(%rsi), %rbp
  mov %rcx, %rsp
  jmpq *%rax
)");

struct Registers {
  void *reg[8];
} ma, co;

void func() {
  std::cout << "Wait!" << std::endl;
  swap_context(&co, &ma);  // yield
  std::cout << "Finish!" << std::endl;
  swap_context(&co, &ma);  // exit
}

int main() {
  std::vector<char> mem(4096);
  void *stack = (char *)((uintptr_t)(&mem.back()) & ~15ull) - sizeof(void *);

  co.reg[4] = (void *)func;
  co.reg[5] = stack;

  swap_context(&ma, &co);  // start coroutine
  std::cout << "Resume" << std::endl;
  swap_context(&ma, &co);  // resume coroutine
  return 0;
}